package com.zhouheng.springbootactiviti.common.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhouheng.common.utils.check.Validators;
import com.zhouheng.springbootactiviti.common.constants.SecurityConstants;
import com.zhouheng.springbootactiviti.common.pojo.SysUserLoginDTO;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;


public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;

    private final HandlerExceptionResolver handlerExceptionResolver;

    public JWTLoginFilter(AuthenticationManager authenticationManager, HandlerExceptionResolver handlerExceptionResolver) {
        this.authenticationManager = authenticationManager;
        this.handlerExceptionResolver = handlerExceptionResolver;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
        try {
            SysUserLoginDTO sysUserLoginDTO = new ObjectMapper().readValue(req.getInputStream(), SysUserLoginDTO.class);
            Map<String, String> validate = Validators.validate(sysUserLoginDTO);
            if (!CollectionUtils.isEmpty(validate)) {
                throw new BadCredentialsException(String.join(",", validate.values()));
            }
            String captcha = sysUserLoginDTO.getCaptcha();
            String sessionCaptcha = (String) req.getSession().getAttribute(SecurityConstants.SESSION_CAPTCHA);
            if (!captcha.equalsIgnoreCase(sessionCaptcha)) {
                throw new BadCredentialsException("验证码错误");
            }
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            sysUserLoginDTO.getUsername(),
                            sysUserLoginDTO.getPassword(),
                            new ArrayList<>())
            );
        } catch (Exception e) {
            // 全局异常捕获后返回响应
            handlerExceptionResolver.resolveException(req, res, null, e);
            // 返回null后会结束鉴权
            return null;
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {
        //subject中存入用户名
        String token = Jwts.builder()
                .setSubject(auth.getName())
                //设置到期时间
                .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 24 * 1000))
                //选择 加密算法和私钥
                .signWith(SignatureAlgorithm.HS512, SecurityConstants.SIGNING_KEY)
                .compact();
        res.addHeader(SecurityConstants.HEADER_AUTH, SecurityConstants.AUTH_HEADER_START_WITH + token);
    }

}
